home *** CD-ROM | disk | FTP | other *** search
Text File | 2002-06-19 | 38.5 KB | 1,456 lines |
- // Copyright (C) 2001-2002 Raven Software.
- //
- // cg_view.c -- setup all the parameters (position, angle, etc)
- // for a 3D rendering
- #include "cg_local.h"
-
- #if !defined(CL_LIGHT_H_INC)
- #include "cg_lights.h"
- #endif
-
- /*
- =============================================================================
-
- MODEL TESTING
-
- The viewthing and gun positioning tools from Q2 have been integrated and
- enhanced into a single model testing facility.
-
- Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
-
- The names must be the full pathname after the basedir, like
- "models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
-
- Testmodel will create a fake entity 100 units in front of the current view
- position, directly facing the viewer. It will remain immobile, so you can
- move around it to view it from different angles.
-
- Testgun will cause the model to follow the player around and supress the real
- view weapon model. The default frame 0 of most guns is completely off screen,
- so you will probably have to cycle a couple frames to see it.
-
- "nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
- frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
- q3default.cfg.
-
- If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
- you adjust the positioning.
-
- Note that none of the model testing features update while the game is paused, so
- it may be convenient to test with deathmatch set to 1 so that bringing down the
- console doesn't pause the game.
-
- =============================================================================
- */
-
- /*
- =================
- CG_TestModel_f
-
- Creates an entity in front of the current position, which
- can then be moved around
- =================
- */
- void CG_TestModel_f (void)
- {
- vec3_t angles;
-
- memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
- if ( trap_Argc() < 2 )
- {
- return;
- }
-
- Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
-
- if ( trap_Argc() == 3 )
- {
- cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
- cg.testModelEntity.frame = 1;
- cg.testModelEntity.oldframe = 0;
- }
-
- if (! cg.testModelEntity.hModel )
- {
- Com_Printf( "Can't register model\n" );
- return;
- }
-
- VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180 + cg.refdef.viewangles[1];
- angles[ROLL] = 0;
-
- AnglesToAxis( angles, cg.testModelEntity.axis );
- }
-
- void CG_TestModelNextFrame_f (void)
- {
- cg.testModelEntity.frame++;
- Com_Printf( "frame %i\n", cg.testModelEntity.frame );
- }
-
- void CG_TestModelPrevFrame_f (void)
- {
- cg.testModelEntity.frame--;
- if ( cg.testModelEntity.frame < 0 )
- {
- cg.testModelEntity.frame = 0;
- }
-
- Com_Printf( "frame %i\n", cg.testModelEntity.frame );
- }
-
- void CG_TestModelNextSkin_f (void)
- {
- cg.testModelEntity.skinNum++;
- Com_Printf( "skin %i\n", cg.testModelEntity.skinNum );
- }
-
- void CG_TestModelPrevSkin_f (void)
- {
- cg.testModelEntity.skinNum--;
- if ( cg.testModelEntity.skinNum < 0 )
- {
- cg.testModelEntity.skinNum = 0;
- }
- Com_Printf( "skin %i\n", cg.testModelEntity.skinNum );
- }
-
- static void CG_AddTestModel (void)
- {
- // re-register the model, because the level may have changed
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
- if (! cg.testModelEntity.hModel )
- {
- Com_Printf ("Can't register model\n");
- return;
- }
-
- trap_R_AddRefEntityToScene( &cg.testModelEntity );
- }
-
- /*
- =================
- CG_CalcVrect
-
- Sets the coordinates of the rendered window
- =================
- */
- static void CG_CalcVrect (void)
- {
- int size;
-
- size = 100;
-
- cg.refdef.width = cgs.glconfig.vidWidth*size/100;
- cg.refdef.width &= ~1;
-
- cg.refdef.height = cgs.glconfig.vidHeight*size/100;
- cg.refdef.height &= ~1;
-
- cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
- cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
- }
-
- //==============================================================================
-
- //==============================================================================
- //==============================================================================
- // this causes a compiler bug on mac MrC compiler
- static void CG_StepOffset( void )
- {
- int timeDelta;
-
- // smooth out stair climbing
- timeDelta = cg.time - cg.stepTime;
- if ( timeDelta < STEP_TIME )
- {
- cg.refdef.vieworg[2] -= cg.stepChange * (STEP_TIME - timeDelta) / STEP_TIME;
- }
- }
-
- #define CAMERA_DAMP_INTERVAL 50
-
- static vec3_t cameramins = { -4, -4, -4 };
- static vec3_t cameramaxs = { 4, 4, 4 };
- vec3_t camerafwd, cameraup;
-
- vec3_t cameraFocusAngles, cameraFocusLoc;
- vec3_t cameraIdealTarget, cameraIdealLoc;
- vec3_t cameraCurTarget={0,0,0}, cameraCurLoc={0,0,0};
- vec3_t cameraOldLoc={0,0,0}, cameraNewLoc={0,0,0};
- int cameraLastFrame=0;
-
- /*
- ===============
- Notes on the camera viewpoint in and out...
-
- cg.refdef.vieworg
- --at the start of the function holds the player actor's origin (center of player model).
- --it is set to the final view location of the camera at the end of the camera code.
- cg.refdef.viewangles
- --at the start holds the client's view angles
- --it is set to the final view angle of the camera at the end of the camera code.
-
- ===============
- */
-
- /*
- ===============
- CG_CalcTargetThirdPersonViewLocation
-
- ===============
- */
- static void CG_CalcIdealThirdPersonViewTarget(void)
- {
- // Initialize IdealTarget
- VectorCopy(cg.refdef.vieworg, cameraFocusLoc);
-
- // Add in the new viewheight
- cameraFocusLoc[2] += cg.snap->ps.viewheight;
-
- // Add in a vertical offset from the viewpoint, which puts the actual target above the head, regardless of angle.
- VectorMA(cameraFocusLoc, 1, cameraup, cameraIdealTarget);
- }
-
-
-
- /*
- ===============
- CG_CalcTargetThirdPersonViewLocation
-
- ===============
- */
- static void CG_CalcIdealThirdPersonViewLocation(void)
- {
- VectorMA(cameraIdealTarget, -(cg_thirdPersonRange.value), camerafwd, cameraIdealLoc);
- }
-
-
-
- static void CG_ResetThirdPersonViewDamp(void)
- {
- trace_t trace;
-
- // Cap the pitch within reasonable limits
- if (cameraFocusAngles[PITCH] > 89.0)
- {
- cameraFocusAngles[PITCH] = 89.0;
- }
- else if (cameraFocusAngles[PITCH] < -89.0)
- {
- cameraFocusAngles[PITCH] = -89.0;
- }
-
- AngleVectors(cameraFocusAngles, camerafwd, NULL, cameraup);
-
- // Set the cameraIdealTarget
- CG_CalcIdealThirdPersonViewTarget();
-
- // Set the cameraIdealLoc
- CG_CalcIdealThirdPersonViewLocation();
-
- // Now, we just set everything to the new positions.
- VectorCopy(cameraIdealLoc, cameraCurLoc);
- VectorCopy(cameraIdealTarget, cameraCurTarget);
-
- // First thing we do is trace from the first person viewpoint out to the new target location.
- CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction <= 1.0)
- {
- VectorCopy(trace.endpos, cameraCurTarget);
- }
-
- // Now we trace from the new target location to the new view location, to make sure there is nothing in the way.
- CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction <= 1.0)
- {
- VectorCopy(trace.endpos, cameraCurLoc);
- }
-
- cameraLastFrame = cg.time;
- }
-
- // This is called every frame.
- static void CG_UpdateThirdPersonTargetDamp(void)
- {
- trace_t trace;
- vec3_t targetdiff;
- float dampfactor, dtime, ratio;
- float damp = 1.0f;
-
- // Set the cameraIdealTarget
- // Automatically get the ideal target, to avoid jittering.
- CG_CalcIdealThirdPersonViewTarget();
-
- if ( damp >=1.0)
- { // No damping.
- VectorCopy(cameraIdealTarget, cameraCurTarget);
- }
- else if ( damp >=0.0)
- {
- // Calculate the difference from the current position to the new one.
- VectorSubtract(cameraIdealTarget, cameraCurTarget, targetdiff);
-
- // Now we calculate how much of the difference we cover in the time allotted.
- // The equation is (Damp)^(time)
- dampfactor = 1.0-damp; // We must exponent the amount LEFT rather than the amount bled off
- dtime = (float)(cg.time-cameraLastFrame) * (1.0/(float)CAMERA_DAMP_INTERVAL); // Our dampfactor is geared towards a time interval equal to "1".
-
- // Note that since there are a finite number of "practical" delta millisecond values possible,
- // the ratio should be initialized into a chart ultimately.
- ratio = powf(dampfactor, (int)dtime);
-
- // This value is how much distance is "left" from the ideal.
- VectorMA(cameraIdealTarget, -ratio, targetdiff, cameraCurTarget);
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
- }
-
- // Now we trace to see if the new location is cool or not.
-
- // First thing we do is trace from the first person viewpoint out to the new target location.
- CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction < 1.0)
- {
- VectorCopy(trace.endpos, cameraCurTarget);
- }
-
- // Note that previously there was an upper limit to the number of physics traces that are done through the world
- // for the sake of camera collision, since it wasn't calced per frame. Now it is calculated every frame.
- // This has the benefit that the camera is a lot smoother now (before it lerped between tested points),
- // however two full volume traces each frame is a bit scary to think about.
- }
-
- // This can be called every interval, at the user's discretion.
- static void CG_UpdateThirdPersonCameraDamp(void)
- {
- trace_t trace;
- vec3_t locdiff;
- float dampfactor, dtime, ratio;
- float damp = 1.0f;
-
- // Set the cameraIdealLoc
- CG_CalcIdealThirdPersonViewLocation();
-
-
- // First thing we do is calculate the appropriate damping factor for the camera.
- dampfactor=0.0;
- if (damp != 0.0)
- {
- double pitch;
-
- // Note that the camera pitch has already been capped off to 89.
- pitch = Q_fabs(cameraFocusAngles[PITCH]);
-
- // The higher the pitch, the larger the factor, so as you look up, it damps a lot less.
- pitch /= 89.0;
- dampfactor = (1.0-damp)*(pitch*pitch);
-
- dampfactor += damp;
- }
-
- if (dampfactor>=1.0)
- { // No damping.
- VectorCopy(cameraIdealLoc, cameraCurLoc);
- }
- else if (dampfactor>=0.0)
- {
- // Calculate the difference from the current position to the new one.
- VectorSubtract(cameraIdealLoc, cameraCurLoc, locdiff);
-
- // Now we calculate how much of the difference we cover in the time allotted.
- // The equation is (Damp)^(time)
- dampfactor = 1.0-dampfactor; // We must exponent the amount LEFT rather than the amount bled off
- dtime = (float)(cg.time-cameraLastFrame) * (1.0/(float)CAMERA_DAMP_INTERVAL); // Our dampfactor is geared towards a time interval equal to "1".
-
- // Note that since there are a finite number of "practical" delta millisecond values possible,
- // the ratio should be initialized into a chart ultimately.
- ratio = powf(dampfactor, (int)dtime);
-
- // This value is how much distance is "left" from the ideal.
- VectorMA(cameraIdealLoc, -ratio, locdiff, cameraCurLoc);
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
- }
-
- // Now we trace from the new target location to the new view location, to make sure there is nothing in the way.
- CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction < 1.0)
- {
- VectorCopy( trace.endpos, cameraCurLoc );
- //FIXME: when the trace hits movers, it gets very very jaggy... ?
- /*
- //this doesn't actually help any
- if ( trace.entityNum != ENTITYNUM_WORLD )
- {
- centity_t *cent = &cg_entities[trace.entityNum];
- gentity_t *gent = &g_entities[trace.entityNum];
- if ( cent != NULL && gent != NULL )
- {
- if ( cent->currentState.pos.trType == TR_LINEAR || cent->currentState.pos.trType == TR_LINEAR_STOP )
- {
- vec3_t diff;
- VectorSubtract( cent->lerpOrigin, gent->currentOrigin, diff );
- VectorAdd( cameraCurLoc, diff, cameraCurLoc );
- }
- }
- }
- */
- }
-
- // Note that previously there was an upper limit to the number of physics traces that are done through the world
- // for the sake of camera collision, since it wasn't calced per frame. Now it is calculated every frame.
- // This has the benefit that the camera is a lot smoother now (before it lerped between tested points),
- // however two full volume traces each frame is a bit scary to think about.
- }
-
- /*
- ===============`
- CG_OffsetThirdPersonView
-
- ===============
- */
- extern vmCvar_t cg_thirdPersonHorzOffset;
- static void CG_OffsetThirdPersonView( void )
- {
- vec3_t diff;
-
- // Set camera viewing direction.
- VectorCopy( cg.refdef.viewangles, cameraFocusAngles );
-
- // if dead, look at killer
- if ( 0 && cg.snap->ps.stats[STAT_HEALTH] <= 0 )
- {
- cameraFocusAngles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
- cameraFocusAngles[PITCH] = 90;
- }
- else
- { // Add in the third Person Angle.
- cameraFocusAngles[YAW] += cg_thirdPersonYaw.value;
- cameraFocusAngles[PITCH] += cg_thirdPersonPitch.value;
- }
-
- // The next thing to do is to see if we need to calculate a new camera target location.
-
- // If we went back in time for some reason, or if we just started, reset the sample.
- if (cameraLastFrame == 0 || cameraLastFrame > cg.time)
- {
- CG_ResetThirdPersonViewDamp();
- }
- else
- {
- // Cap the pitch within reasonable limits
- if (cameraFocusAngles[PITCH] > 89.0)
- {
- cameraFocusAngles[PITCH] = 89.0;
- }
- else if (cameraFocusAngles[PITCH] < -89.0)
- {
- cameraFocusAngles[PITCH] = -89.0;
- }
-
- AngleVectors(cameraFocusAngles, camerafwd, NULL, cameraup);
-
- // Move the target to the new location.
- CG_UpdateThirdPersonTargetDamp();
- CG_UpdateThirdPersonCameraDamp();
- }
-
- // Now interestingly, the Quake method is to calculate a target focus point above the player, and point the camera at it.
- // We won't do that for now.
-
- // We must now take the angle taken from the camera target and location.
- VectorSubtract(cameraCurTarget, cameraCurLoc, diff);
- VectorNormalize(diff);
- vectoangles(diff, cg.refdef.viewangles);
-
- // Temp: just move the camera to the side a bit
- if ( cg_thirdPersonHorzOffset.value != 0.0f )
- {
- AnglesToAxis( cg.refdef.viewangles, cg.refdef.viewaxis );
- VectorMA( cameraCurLoc, cg_thirdPersonHorzOffset.value, cg.refdef.viewaxis[1], cameraCurLoc );
- }
-
- // ...and of course we should copy the new view location to the proper spot too.
- VectorCopy(cameraCurLoc, cg.refdef.vieworg);
-
- cameraLastFrame=cg.time;
- }
-
-
-
- /*
- ===============
- CG_OffsetThirdPersonView
-
- ===============
- *//*
- #define FOCUS_DISTANCE 512
- static void CG_OffsetThirdPersonView( void ) {
- vec3_t forward, right, up;
- vec3_t view;
- vec3_t focusAngles;
- trace_t trace;
- static vec3_t mins = { -4, -4, -4 };
- static vec3_t maxs = { 4, 4, 4 };
- vec3_t focusPoint;
- float focusDist;
- float forwardScale, sideScale;
-
- cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
-
- VectorCopy( cg.refdef.viewangles, focusAngles );
-
- // if dead, look at killer
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- cg.refdef.viewangles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- }
-
- if ( focusAngles[PITCH] > 45 ) {
- focusAngles[PITCH] = 45; // don't go too far overhead
- }
- AngleVectors( focusAngles, forward, NULL, NULL );
-
- VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
-
- VectorCopy( cg.refdef.vieworg, view );
-
- view[2] += 8;
-
- cg.refdef.viewangles[PITCH] *= 0.5;
-
- AngleVectors( cg.refdef.viewangles, forward, right, up );
-
- forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
- sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
- VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
- VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
-
- // trace a ray from the origin to the viewpoint to make sure the view isn't
- // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
-
- if (!cg_cameraMode.integer) {
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
-
- if ( trace.fraction != 1.0 ) {
- VectorCopy( trace.endpos, view );
- view[2] += (1.0 - trace.fraction) * 32;
- // try another trace to this position, because a tunnel may have the ceiling
- // close enogh that this is poking out
-
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
- VectorCopy( trace.endpos, view );
- }
- }
-
-
- VectorCopy( view, cg.refdef.vieworg );
-
- // select pitch to look at focus point from vieword
- VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
- focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
- if ( focusDist < 1 ) {
- focusDist = 1; // should never happen
- }
- cg.refdef.viewangles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
- cg.refdef.viewangles[YAW] -= cg_thirdPersonAngle.value;
- }
-
-
- // this causes a compiler bug on mac MrC compiler
- static void CG_StepOffset( void ) {
- int timeDelta;
-
- // smooth out stair climbing
- timeDelta = cg.time - cg.stepTime;
- if ( timeDelta < STEP_TIME ) {
- cg.refdef.vieworg[2] -= cg.stepChange
- * (STEP_TIME - timeDelta) / STEP_TIME;
- }
- }*/
-
- /*
- ===============
- CG_OffsetFirstPersonView
- ===============
- */
- static void CG_OffsetFirstPersonView( void )
- {
- float *origin;
- float *angles;
- float bob;
- float ratio;
- float delta;
- float speed;
- float f;
- vec3_t predictedVelocity;
- int timeDelta;
- vec3_t right;
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- return;
- }
-
- origin = cg.refdef.vieworg;
- angles = cg.refdef.viewangles;
-
- // If dead, fall to the ground
- if ( cg.snap->ps.pm_type == PM_DEAD )
- {
- int atime;
- int htime;
- float f;
-
- atime = (cg.time - cg.deathTime);
- if ( atime > 450)
- {
- atime = 450;
- }
-
- htime = (cg.time - cg.deathTime);
- if ( htime > 350)
- {
- htime = 350;
- }
-
- f = (float)atime / 450.0f;
- cg.refdef.viewangles[ROLL] += ((cg.deathTime&0x100)?-1:1) * 40 * f;
- cg.refdef.viewangles[PITCH] -= ((cg.deathTime&0x010)?-1:1) * 20 * f;
- cg.refdef.viewangles[YAW] -= ((cg.deathTime&0x001)?-1:1) * 40 * f;
-
- f = (float)htime / 400.0f;
- cg.refdef.vieworg[2] += (f * cg.predictedPlayerState.viewheight * 0.90f);
-
- return;
- }
-
- // add angles based on damage kick
- if ( cg.damageTime )
- {
- ratio = cg.time - cg.damageTime;
- if ( ratio < DAMAGE_DEFLECT_TIME )
- {
- ratio /= DAMAGE_DEFLECT_TIME;
- angles[PITCH] += ratio * cg.v_dmg_pitch;
-
- if ( cg.v_dmg_roll != 255 )
- {
- angles[ROLL] += ratio * cg.v_dmg_roll;
- }
- }
- else
- {
- ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
- if ( ratio > 0 )
- {
- angles[PITCH] += ratio * cg.v_dmg_pitch;
-
- if ( cg.v_dmg_roll != 255 )
- {
- angles[ROLL] += ratio * cg.v_dmg_roll;
- }
- }
- }
- }
-
- // add pitch based on fall kick
- #if 0
- ratio = ( cg.time - cg.landTime) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- angles[PITCH] += ratio * cg.fall_value;
- #endif
-
- // add angles based on velocity
- VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
- angles[PITCH] += delta * cg_runpitch.value;
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
- angles[ROLL] -= delta * cg_runroll.value;
-
- // add angles based on bob
-
- // make sure the bob is visible even at low speeds
- speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
-
- delta = cg.bobfracsin * cg_bobpitch.value * speed;
- if ((cg.predictedPlayerState.pm_flags & PMF_DUCKED) && (cg.predictedPlayerState.groundEntityNum!=ENTITYNUM_NONE))
- delta *= 3; // crouching
- angles[PITCH] += delta;
- delta = cg.bobfracsin * cg_bobroll.value * speed;
- if ((cg.predictedPlayerState.pm_flags & PMF_DUCKED) && (cg.predictedPlayerState.groundEntityNum!=ENTITYNUM_NONE))
- delta *= 3; // crouching accentuates roll
- if (cg.bobcycle & 1)
- delta = -delta;
- angles[ROLL] += delta;
-
- //===================================
-
- // add view height
- origin[2] += cg.predictedPlayerState.viewheight;
-
- // smooth out duck height changes
- timeDelta = cg.time - cg.duckTime;
- if ( timeDelta < DUCK_TIME) {
- cg.refdef.vieworg[2] -= cg.duckChange
- * (DUCK_TIME - timeDelta) / DUCK_TIME;
- }
-
- // add bob height
- bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
- if (bob > 6) {
- bob = 6;
- }
-
- origin[2] += bob;
-
-
- // add fall height
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- f = delta / LAND_DEFLECT_TIME;
- cg.refdef.vieworg[2] += cg.landChange * f;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- delta -= LAND_DEFLECT_TIME;
- f = 1.0 - ( delta / LAND_RETURN_TIME );
- cg.refdef.vieworg[2] += cg.landChange * f;
- }
-
- // add step offset
- CG_StepOffset();
-
- // add kick offset
-
- if( cg.predictedPlayerState.pm_flags & PMF_LEANING )
- {
- float leanOffset;
-
- leanOffset = (float)(cg.predictedPlayerState.leanTime - LEAN_TIME) / LEAN_TIME * LEAN_OFFSET;
- angles[ROLL] += leanOffset / 4;
- AngleVectors( cg.predictedPlayerState.viewangles, NULL, right, NULL );
- VectorMA( origin, leanOffset, right, origin );
- }
-
- // Make sure view doesnt invert on itself
- angles[PITCH] = Com_Clampf ( -89, 89, angles[PITCH] );
- }
-
-
- /*
- ====================
- CG_CalcFovFromX
-
- Calcs Y FOV from given X FOV
- ====================
- */
- #define WAVE_AMPLITUDE 1
- #define WAVE_FREQUENCY 0.4
-
- qboolean CG_CalcFOVFromX( float fov_x )
- {
- float x;
- // float phase;
- // float v;
- // int contents;
- float fov_y;
- qboolean inwater;
-
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
-
- // there's a problem with this, it only takes the leafbrushes into account, not the entity brushes,
- // so if you give slime/water etc properties to a func_door area brush in order to move the whole water
- // level up/down this doesn't take into account the door position, so warps the view the whole time
- // whether the water is up or not. Fortunately there's only one slime area in Trek that you can be under,
- // so lose it...
- #if 0
- /*
- // warp if underwater
- contents = CG_PointContents( cg.refdef.vieworg, -1 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_LAVA ) ){
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
- v = WAVE_AMPLITUDE * sin( phase );
- fov_x += v;
- fov_y -= v;
- inwater = qtrue;
- }
- else {
- inwater = qfalse;
- }
- */
- #else
- inwater = qfalse;
- #endif
-
-
- // set it
- cg.refdef.fov_x = fov_x;
- cg.refdef.fov_y = fov_y;
-
- return (inwater);
- }
-
- /*
- ====================
- CG_CalcFov
-
- Fixed fov at intermissions, otherwise account for fov variable and zooms.
- ====================
- */
- #define WAVE_AMPLITUDE 1
- #define WAVE_FREQUENCY 0.4
-
- static int CG_CalcFov( void ) {
- float x;
- float phase;
- float v;
- int contents;
- float fov_x, fov_y;
- float zoomFov;
- float f;
- int inwater;
-
- if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- // if in intermission, use a fixed value
- fov_x = 90;
- }
- else
- {
- // user selectable
- if ( cgs.dmflags & DF_FIXED_FOV )
- {
- // dmflag to prevent wide fov for all clients
- fov_x = 90;
- }
- else
- {
- fov_x = cg_fov.value;
- if ( fov_x < 1 )
- {
- fov_x = 1;
- }
- else if ( fov_x > 160 )
- {
- fov_x = 160;
- }
- }
-
- // If cheats arent enabled then 80 is the lowest and 100 is the highest
- if ( !cg.cheats )
- {
- if ( fov_x < 80 )
- {
- fov_x = 80;
- }
- else if ( fov_x > 100 )
- {
- fov_x = 100;
- }
- }
-
- if ( cg.predictedPlayerState.pm_flags & PMF_ZOOMED )
- {
- zoomFov = (float)cg.predictedPlayerState.zoomFov;
-
- if (!cg.predictedPlayerState.pm_flags & PMF_ZOOM_LOCKED )
- {
- zoomFov -= cg.frametime * 0.05f;
-
- if (zoomFov < MAX_ZOOM_FOV)
- {
- zoomFov = MAX_ZOOM_FOV;
- }
- else if (zoomFov > cg_fov.value)
- {
- zoomFov = cg_fov.value;
- }
- else
- { // Still zooming
- static zoomSoundTime = 0;
-
- if (zoomSoundTime < cg.time || zoomSoundTime > cg.time + 10000)
- {
- zoomSoundTime = cg.time + 300;
- }
- }
- }
-
- fov_x = zoomFov;
- }
- else
- {
- f = ( cg.time - cg.predictedPlayerState.zoomTime ) / ZOOM_OUT_TIME;
- if ( f > 1.0 )
- {
- fov_x = fov_x;
- }
- else
- {
- fov_x = cg.predictedPlayerState.zoomFov + f * ( fov_x - cg.predictedPlayerState.zoomFov );
- }
- }
- }
-
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
-
- // warp if underwater
- contents = CG_PointContents( cg.refdef.vieworg, -1 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_LAVA ) ){
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
- v = WAVE_AMPLITUDE * sin( phase );
- fov_x += v;
- fov_y -= v;
- inwater = qtrue;
- }
- else {
- inwater = qfalse;
- }
-
- // set it
- cg.refdef.fov_x = fov_x;
- cg.refdef.fov_y = fov_y;
-
- if ( !(cg.predictedPlayerState.pm_flags&PMF_ZOOMED) )
- {
- cg.zoomSensitivity = 1;
- }
- else
- {
- cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
- }
-
- return inwater;
- }
-
- static void CG_DamageBlendBlob( void )
- {
- int t = 250;
- int maxTime = DAMAGE_TIME;
- vec3_t lineStart;
- vec3_t lineEnd;
- vec3_t rgb1;
- vec3_t rgb2;
- qboolean dmgIsToTheLeft;
- qboolean dmgIsAbove;
- qboolean unknownDir;
- float alphaVal;
- float cvarScale;
-
- if (cg_damageindicator.value <= 0)
- {
- return;
- }
-
- t = cg.time - cg.damageTime;
- if ( t <= 0 || t >= maxTime )
- {
- return;
- }
-
- // here we use cg.damageY as a value to indicate how much above you the damage is and
- //cg.damageX as a value to indicate how much to your left the damage is
-
- // draw a "line" using the cgs.media.damageDirShader
- dmgIsToTheLeft = (cg.damageX > 0);
- dmgIsAbove = (cg.damageY < 0);
- unknownDir = (cg.v_dmg_roll == 255);
- alphaVal = ( 1.0 - ((float)t / maxTime) );
- cvarScale = 1.0f * cg_damageindicator.value;
-
- VectorSet(rgb1, 1, 1, 1);
- VectorSet(rgb2, 1, 1, 1);
-
- // draw the left/right indicator if it's far enough from center
- if ( (fabs(cg.damageX) > 25) || unknownDir)
- {
- VectorMA(cg.refdef.vieworg, 20, cg.refdef.viewaxis[0], lineStart);
- VectorMA(lineStart, (dmgIsToTheLeft?6:-6), cg.refdef.viewaxis[1], lineStart);
- VectorMA(lineStart, (dmgIsToTheLeft?2:-2)*cvarScale, cg.refdef.viewaxis[1], lineEnd);
-
- trap_FX_AddLine( lineStart, lineEnd,
- 5.0f*cvarScale, 5.0f*cvarScale, 0.0f,
- alphaVal, alphaVal, 0.0f,
- rgb1, rgb2, 0.0f,
- 1, cgs.media.damageDirShader, FX_DEPTH_HACK );
- }
- if (unknownDir)
- {
- // dmg from unknown direction...display all four directions
- VectorMA(cg.refdef.vieworg, 20, cg.refdef.viewaxis[0], lineStart);
- VectorMA(lineStart, (dmgIsToTheLeft?-6:6), cg.refdef.viewaxis[1], lineStart);
- VectorMA(lineStart, (dmgIsToTheLeft?-2:2)*cvarScale, cg.refdef.viewaxis[1], lineEnd);
-
- trap_FX_AddLine( lineStart, lineEnd,
- 5.0f*cvarScale, 5.0f*cvarScale, 0.0f,
- alphaVal, alphaVal, 0.0f,
- rgb1, rgb2, 0.0f,
- 1, cgs.media.damageDirShader, FX_DEPTH_HACK );
- }
-
- // draw the above/below indicator
- if ( (fabs(cg.damageY) > 15) || unknownDir)
- {
- VectorMA(cg.refdef.vieworg, 20, cg.refdef.viewaxis[0], lineStart);
- VectorMA(lineStart, (dmgIsAbove?6:-6), cg.refdef.viewaxis[2], lineStart);
- VectorMA(lineStart, (dmgIsAbove?2:-2)*cvarScale, cg.refdef.viewaxis[2], lineEnd);
-
- trap_FX_AddLine( lineStart, lineEnd,
- 5.0f*cvarScale, 5.0f*cvarScale, 0.0f,
- alphaVal, alphaVal, 0.0f,
- rgb1, rgb2, 0.0f,
- 1, cgs.media.damageDirShader, FX_DEPTH_HACK );
- }
- if (unknownDir)
- {
- VectorMA(cg.refdef.vieworg, 20, cg.refdef.viewaxis[0], lineStart);
- VectorMA(lineStart, (dmgIsAbove?-6:6), cg.refdef.viewaxis[2], lineStart);
- VectorMA(lineStart, (dmgIsAbove?-2:2)*cvarScale, cg.refdef.viewaxis[2], lineEnd);
-
- trap_FX_AddLine( lineStart, lineEnd,
- 5.0f*cvarScale, 5.0f*cvarScale, 0.0f,
- alphaVal, alphaVal, 0.0f,
- rgb1, rgb2, 0.0f,
- 1, cgs.media.damageDirShader, FX_DEPTH_HACK );
- }
- }
-
- /*
- ===============
- CG_CalcViewValues
-
- Sets cg.refdef view values
- ===============
- */
- static int CG_CalcViewValues( void )
- {
- playerState_t *ps;
-
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
-
- // strings for in game rendering
- // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
- // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
-
- // calculate size of 3D view
- CG_CalcVrect();
-
- ps = &cg.predictedPlayerState;
- /*
- if (cg.cameraMode) {
- vec3_t origin, angles;
- if (trap_getCameraInfo(cg.time, &origin, &angles)) {
- VectorCopy(origin, cg.refdef.vieworg);
- angles[ROLL] = 0;
- VectorCopy(angles, cg.refdef.viewangles);
- AnglesToAxis( cg.refdef.viewangles, cg.refdef.viewaxis );
- return CG_CalcFov();
- } else {
- cg.cameraMode = qfalse;
- }
- }
- */
- // intermission view
- if ( ps->pm_type == PM_INTERMISSION )
- {
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdef.viewangles );
- AnglesToAxis( cg.refdef.viewangles, cg.refdef.viewaxis );
- return CG_CalcFov();
- }
-
- cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
- cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
- cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
- ps->velocity[1] * ps->velocity[1] );
-
-
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdef.viewangles );
-
- if (cg_cameraOrbit.integer)
- {
- if (cg.time > cg.nextOrbitTime)
- {
- cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
- cg_thirdPersonYaw.value += cg_cameraOrbit.value;
- }
- }
-
- // add error decay
- if ( cg_errorDecay.value > 0 )
- {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f > 0 && f < 1 ) {
- VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
- } else {
- cg.predictedErrorTime = 0;
- }
- }
-
- if ( cg.renderingThirdPerson && !(cg.snap->ps.pm_flags & PMF_ZOOMED) )
- {
- // back away from character
- CG_OffsetThirdPersonView();
- }
- else
- {
- // offset for local bobbing and kicks
- CG_OffsetFirstPersonView();
- }
-
- CG_UpdateCameraShake ( cg.refdef.vieworg, cg.refdef.viewangles );
-
- // position eye reletive to origin
- AnglesToAxis( cg.refdef.viewangles, cg.refdef.viewaxis );
-
- if ( cg.hyperspace ) {
- cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
- }
-
- // field of view
- return CG_CalcFov();
- }
-
- /*
- =====================
- CG_AddBufferedSound
- =====================
- */
- void CG_AddBufferedSound( sfxHandle_t sfx ) {
- if ( !sfx )
- return;
- cg.soundBuffer[cg.soundBufferIn] = sfx;
- cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
- if (cg.soundBufferIn == cg.soundBufferOut) {
- cg.soundBufferOut++;
- }
- }
-
- /*
- =====================
- CG_PlayBufferedSounds
- =====================
- */
- static void CG_PlayBufferedSounds( void ) {
- if ( cg.soundTime < cg.time ) {
- if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
- trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
- cg.soundBuffer[cg.soundBufferOut] = 0;
- cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
- cg.soundTime = cg.time + 750;
- }
- }
- }
-
- //=========================================================================
-
- /*
- =================
- CG_UpdateRogerWilco
-
- Updates the roger wilco team you are on
- =================
- */
- void CG_UpdateRogerWilco ( void )
- {
- qboolean dead = qfalse;
-
- if ( !rw_enabled.integer )
- {
- return;
- }
-
- if ( cgs.clientinfo[cg.clientNum].team != TEAM_SPECTATOR )
- {
- if ( cgs.gametypeData->respawnType == RT_NONE )
- {
- if ( cg.predictedPlayerState.pm_flags & (PMF_GHOST|PMF_FOLLOW) || cg.predictedPlayerState.pm_type == PM_DEAD )
- {
- dead = qtrue;
- }
- }
- }
-
- trap_RW_SetTeam(cgs.clientinfo[cg.clientNum].team, dead);
- }
-
- /*
- =================
- CG_DrawActiveFrame
-
- Generates and draws a game scene and status information at the given time.
- =================
- */
- void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
- int inwater;
-
- cg.time = serverTime;
- cg.demoPlayback = demoPlayback;
-
- // update cvars
- CG_UpdateCvars();
-
- // if we are only updating the screen as a loading
- // pacifier, don't even try to read snapshots
- if ( cg.infoScreenText[0] != 0 ) {
- CG_DrawInformation();
- return;
- }
-
- trap_FX_AdjustTime( cg.time );
-
- CG_UpdateRogerWilco ( );
-
- CG_RunLightStyles();
-
- // any looped sounds will be respecified as entities
- // are added to the render list
- trap_S_ClearLoopingSounds(qfalse);
-
- // clear all the render lists
- trap_R_ClearScene();
-
- // set up cg.snap and possibly cg.nextSnap
- CG_ProcessSnapshots();
-
- // if we haven't received any snapshots yet, all
- // we can draw is the information screen
- if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_DrawInformation();
- return;
- }
-
- // Handle last weapon selection
- if ( cg.weaponSelect != cg.weaponOldSelect )
- {
- cg.weaponLastSelect = cg.weaponOldSelect;
- cg.weaponOldSelect = cg.weaponSelect;
- }
-
- // let the client system know what our weapon and zoom settings are
- if ( cg.weaponMenuUp )
- {
- trap_SetUserCmdValue( (cg.weaponMenuSelect | WP_DELAYED_CHANGE_BIT), cg.zoomSensitivity );
- }
- else
- {
- trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
- }
-
- // this counter will be bumped for every valid scene we generate
- cg.clientFrame++;
-
- // update cg.predictedPlayerState
- CG_PredictPlayerState();
-
- // update the scores from the playerstate
- if ( cgs.scores1 != cg.predictedPlayerState.persistant[PERS_RED_SCORE] )
- {
- cgs.scores1 = cg.predictedPlayerState.persistant[PERS_RED_SCORE];
- trap_Cvar_Set ( "ui_info_redscore", va("%d", cgs.scores1 ) );
- }
-
- if ( cgs.scores2 != cg.predictedPlayerState.persistant[PERS_BLUE_SCORE] )
- {
- cgs.scores2 = cg.predictedPlayerState.persistant[PERS_BLUE_SCORE];
- trap_Cvar_Set ( "ui_info_bluescore", va("%d", cgs.scores2 ) );
- }
-
- // decide on third person view
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR || (cg.snap->ps.pm_flags & PMF_GHOST))
- {
- cg.renderingThirdPerson = qfalse;
- }
- else if ( cg.snap->ps.pm_type == PM_DEAD )
- {
- cg.renderingThirdPerson = cg_thirdPerson.integer;
- }
- else
- {
- if ( cg.snap->ps.pm_flags & PMF_ZOOMED )
- {
- cg.renderingThirdPerson = qfalse;
- }
- else if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
- {
- cg.renderingThirdPerson = qtrue;
- }
- else
- {
- cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
- }
- }
-
- // build cg.refdef
- inwater = CG_CalcViewValues();
-
- // first person blend blobs, done after AnglesToAxis
- if ( !cg.renderingThirdPerson ) {
- CG_DamageBlendBlob();
- }
-
- // Load deferred models
- if ( cg.deferredPlayerLoading > 10 )
- {
- CG_LoadDeferredPlayers();
- cg.deferredPlayerLoading = 0;
- }
-
- // build the render lists
- if ( !cg.hyperspace )
- {
- CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
- CG_AddLocalEntities();
- CG_DrawMiscEnts();
- }
-
- if ( cg.snap->ps.stats[STAT_HEALTH] > 0 )
- {
- CG_AnimateViewWeapon(&cg.predictedPlayerState);
- CG_AddViewWeapon( &cg.predictedPlayerState );
- }
-
- if ( !cg.hyperspace )
- {
- trap_FX_AddScheduledEffects();
- }
-
- // add buffered sounds
- CG_PlayBufferedSounds();
-
- // play buffered voice chats
- CG_PlayBufferedVoiceChats();
-
- // finish up the rest of the refdef
- if ( cg.testModelEntity.hModel ) {
- CG_AddTestModel();
- }
- cg.refdef.time = cg.time;
- memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
-
- // update audio positions
- if ( !cg.mMapChange )
- {
- trap_AS_UpdateAmbientSet( CG_ConfigString( CS_AMBIENT_SOUNDSETS ), cg.refdef.vieworg ); // MUST be before trap_S_Respatialize()! -ste
- trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
- }
-
- // make sure the lagometerSample and frame timing isn't done twice when in stereo
- if ( stereoView != STEREO_RIGHT ) {
- cg.frametime = cg.time - cg.oldTime;
- if ( cg.frametime < 0 ) {
- cg.frametime = 0;
- }
- cg.oldTime = cg.time;
- CG_AddLagometerFrameInfo();
- }
-
- // actually issue the rendering calls
- CG_DrawActive( stereoView );
-
- if ( cg_stats.integer )
- {
- Com_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
- }
- }
-
- /*
- =================
- CG_CameraShake
-
- Shakes the camera a bit (used in grenades)
- =================
- */
- #define MAX_SHAKE_INTENSITY 2.0f
- #define DEFAULT_EXPLOSION_RADIUS 400
-
- void CG_CameraShake ( float* origin, float intensity, int radius, int time )
- {
- vec3_t dir;
- float dist, intensityScale;
- float realIntensity;
-
- VectorSubtract( cg.refdef.vieworg, origin, dir );
- dist = VectorNormalize( dir );
-
- // Apparently the SoF2 camera shake function takes a time, but not a radius.
- // when someone feels like fixing this, we can be a bit more flexible
- radius = DEFAULT_EXPLOSION_RADIUS;
-
- //Use the dir to add kick to the explosion
- if ( dist > radius )
- return;
-
- intensityScale = 1 - ( dist / (float) radius );
- realIntensity = intensity * intensityScale;
-
- if ( realIntensity > MAX_SHAKE_INTENSITY )
- realIntensity = MAX_SHAKE_INTENSITY;
-
- cg.shakeIntensity = realIntensity;
- cg.shakeDuration = time;
- cg.shakeStart = cg.time;
- }
-
- /*
- =================
- CG_UpdateCameraShake
-
- Updates the camera shake
- =================
- */
- void CG_UpdateCameraShake ( vec3_t origin, vec3_t angles )
- {
- vec3_t moveDir;
- float intensity_scale;
- float intensity;
- int i;
-
- if ( cg.shakeDuration <= 0 )
- return;
-
- if ( cg.time > ( cg.shakeStart + cg.shakeDuration ) )
- {
- cg.shakeIntensity = 0;
- cg.shakeDuration = 0;
- cg.shakeStart = 0;
- return;
- }
-
- //intensity_scale now also takes into account FOV with 90.0 as normal
- intensity_scale = 1.0f - ( (float) ( cg.time - cg.shakeStart ) / (float) cg.shakeDuration ) * (((cg.refdef.fov_x+cg.refdef.fov_y)/2.0f)/90.0f);
- intensity = cg.shakeIntensity * intensity_scale;
-
- for ( i = 0; i < 3; i++ )
- {
- moveDir[i] = flrand(-intensity, intensity );
- }
-
- //FIXME: Lerp
-
- //Move the camera
- VectorAdd( origin, moveDir, origin );
-
- for ( i = 0; i < 3; i++ )
- {
- moveDir[i] = flrand(-intensity, intensity );
- }
-
- //FIXME: Lerp
-
- //Move the angles
- VectorAdd( angles, moveDir, angles );
- }
-